; 3step.asm ; (C)2007 Chris Hellyar. ; Released as open source under the GPL ; Details of the hardware can be found at http://www.ohmark.co.nz/3step. ; originally published as a result of a thread on the message boards at http://www.cnczone.com ; if you find this useful, drop me an email: chris@trash.co.nz and let me know what you throught! ; ***************** NOTE: *********************** ; Please check the circuit details before using this in your own design circuit! ; The step inputs pulse low as ouputs for 1 instruction cycle to clear ; a capacitor 'latch' circuit, so if you hook this directly to a parallel port ; or other device you might cause 'issues'. ; The circuit diagram is at the website address above. ; 7/4/07 V0.9 starting the code, like. ; 8/4/07 V0.9 Starting work on optimisation. ; 19/4/07 V1.0 Cleaning up test code, getting ready to 'release' it. So to speak. ; - Added flashing estop LED funcitonality, and removed test 1/8th stepping code ; - Changed inhibit to use TRIS bits rather than clearing port - no steps are ; lost if you estop it when not moving. ; - dropped quite a few cycles from the xstep and ystep routines ; - added watchdog reset SOS flashing code. Cute. radix dec ; default number type decimal. ; set processor type etc. list p=16F870 ; list directive to define processor #include ; processor specific variable definitions __CONFIG _CP_OFF & _BODEN_OFF &_PWRTE_OFF&_WDT_ON&_LVP_OFF& _HS_OSC&_DEBUG_OFF __IDLOCS H'0100' ; defines etc for inputs/outputs ; inputs #define xstep PORTC,0 ; x step input. #define xdir PORTC,1 ; x direction input. #define ystep PORTC,2 ; y step input #define ydir PORTC,3 ; y direction input. #define zstep PORTC,4 ; z step input #define zdir PORTC,5 ; z dir input #define fhjump PORTA,4 ; full/half jumper. half=0 full=1 #define enable PORTC,6 ; active low enable pin for all motors.. #define led PORTC,7 ; output for LED on estop.. Flashes when in estop.. ; I/O mode stuff, unused (0V on pcb) are inputs, keeps it tidy. ; 0 is output, 1 is input. amode equ B'11010000' ; Port A amodeo equ B'11011111' ; Port A when outputs are disabled... bmode equ B'00000000' ; Port B bmodeo equ B'11111111' ; Port B when outputs are disabled... cmode equ B'01111111' ; Port C ; misc equates ops equ B'10001111' ; options register. ; definitions of "Variables" #define rambase 20h ; begining of ram on PIC16F870 x equ rambase ; temp counter used in loops y equ rambase+1 ; temp counter. z equ rambase+2 stat equ rambase+3 ; byte used to flag status of step inputs for edge triggering... xpos equ rambase+4 ; position in step table for x ypos equ rambase+5 ; position in step table for y zpos equ rambase+6 ; position in step table for z ynib equ rambase+7 ; temp storage of Y nibble, speeds up x and y output as they share a port. xnib equ rambase+8 ; temp storage of X nibble, speeds up x and y output as they share a port. #define xstat stat,0 ; x bit in status flag byte. #define ystat stat,1 ; y bit in status flag byte type thingit. #define zstat stat,2 ; you guessed it, z bit in status flag byte. ;********************************************************** ; The code starts here.. org 0 ; reset vector ; first up, test for non-power on reset. (Watchdog kicked it) bsf STATUS,RP0 ; registerpage 1 for PCON register. btfsc PCON,NOT_POR ; if POR is 0 everything is OK if it's 1 a watchdog reset occured. goto sos ; do sos flashes if it had a watchdog reset.. bcf STATUS,RP0 ; select register page 0 again. begin movlw 1 ; one loop through the delay... call ldelay ; startup delay, not sure why, but it seems like a nice idea. clrf PORTB ; clear output bits, just in case. clrf PORTC bsf STATUS,RP0 ; select register page 1 for option etc. bsf PCON,NOT_POR ; set power on reset flag in PCON movlw ops ; setup wdt prescaler before pic resets! movwf OPTION_REG ; load option register movlw 6 ; configure all port A ports as digital. movwf ADCON1 movlw amode ; set pin I/O modes. movwf TRISA movlw bmode ; set I/O modes of general ports... movwf TRISB movlw cmode movwf TRISC bcf STATUS,RP0 ; select register page 0 again. goto main ; skips over subroutines. Subs have to be in the first page of program memory. ;********************************************************* ; subroutines under here ; subroutines are in first page of program memory ; long delay, for flashing LED (Rocket science) ; on entry w contains number of loops around.. ldelay movwf z ldelay1 movlw 255 movwf y ldelay2 movlw 255 movwf x clrwdt ; clear watchdog, so it dosn't bomb during the led flashing... ldelay3 nop ; padding. decfsz x,f goto ldelay3 decfsz y,f goto ldelay2 decfsz z,f goto ldelay1 return ; step tables... ; using seperate ones for high and low nibble to save a couple of instruction cycles. ; step table for low nibble (X and Z) steptabl andlw B'00000111' ; mask input to 3 bits. (8 steps) btfss fhjump goto halftabl ; if the F/H input is low, go to half stepping table.. addwf PCL,f ; add offset to program counter.. retlw B'00000011' ; full stepping table. retlw B'00000110' retlw B'00001100' retlw B'00001001' retlw B'00000011' retlw B'00000110' retlw B'00001100' retlw B'00001001' halftabl addwf PCL,f ; add offset to program counter. retlw B'00000001' ; half stepping table. retlw B'00000011' retlw B'00000010' retlw B'00000110' retlw B'00000100' retlw B'00001100' retlw B'00001000' retlw B'00001001' ; step table for high nibble (Y) steptabh andlw B'00000111' ; mask input to 3 bits. (8 steps) btfss fhjump goto halftabh ; if the F/H input is low, go to half stepping table.. addwf PCL,f ; add offset to program counter.. retlw B'00110000' ; full stepping table. retlw B'01100000' retlw B'11000000' retlw B'10010000' retlw B'00110000' ; full stepping table. retlw B'01100000' retlw B'11000000' retlw B'10010000' halftabh addwf PCL,f ; add offset to program counter. retlw B'00010000' ; half stepping table. retlw B'00110000' retlw B'00100000' retlw B'01100000' retlw B'01000000' retlw B'11000000' retlw B'10000000' retlw B'10010000' ; step x xdostep bsf xstat ; set X status bit to high as we've just gone high... btfss xdir ; check dir input, skip if high goto xup ; going up! xdn decf xpos,f ; decrement position in table, result in w (xdn not used, here for readability) ; stepout code, moved from subroutine, save 4 cycles. movfw xpos ; get X position. call steptabl ; get nibble for X movwf xnib ; store it for later... iorwf ynib,w ; or it with Y nibble. movwf PORTB ; stick it out the port already. return xup incf xpos,f ; increment position in step table. ; stepout code, moved from subroutine, save 4 cycles. movfw xpos ; get X position call steptabl ; get nibble for X movwf xnib ; store it for later... iorwf ynib,w ; or it with X nibble. movwf PORTB ; stick it out the port already. return ; step y ydostep bsf ystat ; set X status bit to high as we've just gone high... btfss ydir ; check dir input, skip if high goto yup ; going up! ydn decf ypos,f ; decrement position in table, result in w (ydn not used, for readability) ; stepout code, moved from subroutine, save 4 cycles. movfw ypos ; get Y call steptabh ; get high nibble for Y movwf ynib ; store it for later. iorwf xnib,w ; OR it with X nibble. movwf PORTB ; stick it out... return yup incf ypos,f ; increment position in step table. ; stepout code, moved from subroutine, save 4 cycles. movfw ypos ; get Y call steptabh ; get high nibble for Y movwf ynib ; store it for later. iorwf xnib,w ; OR it with X nibble. movwf PORTB ; stick it out... return ; step z zdostep bsf zstat ; set X status bit to high as we've just gone high... btfss zdir ; check dir input, skip if high goto zup ; going up! zdn decf zpos,f ; decrement position in table, result in w (zdn not used, for readability) ; stepout code, moved from subroutine, save 4 cycles. movfw zpos ; get Z call steptabl ; look it up in low nibble table. movwf PORTA ; stick it out... return zup incf zpos,f ; increment position in step table. ; goto zup ; for testing wdt, should be commented out! ; stepout code, moved from subroutine, save 4 cycles. movfw zpos ; get Z call steptabl ; look it up. movwf PORTA ; stick it out... return ; outahere. ;***************************************************** ; code starts here. main clrf stat ; clear the level status byte... clrf PORTC ; port output latches need to be 0 to discharge step input caps.. clrf ynib ; clear temp nibble settings for y and x clrf xnib clrf PORTA ; turn off Z until something steps it.. ; Below here is the main program loopy thing. loop clrwdt ; clear watchdog btfsc enable ; if enable bit is low, do the loopy thing. goto noten ; but if it's not enabled, go fish.. btfsc xstat ; check to see if we're looking for high or low on x goto xhigh ; it was high, we're looking for it to go low. xlow btfsc xstep ; check step input for x skip if 0 (xlow tag not used, for reading code only) call xdostep ; if it has gone high step x.. goto ynext ; do y next... ; attempt to discharge cap on ystep input. xhigh bsf STATUS,RP0 ; select register page 1 for option etc. bcf TRISC,0 ; turn it into an output for 0.2us, which will discharge the cap, like. bsf TRISC,0 bcf STATUS,RP0 ; select register page 0 again. btfss xstep ; check the input, see if it's gone low. bcf xstat ; clear status. ynext btfsc ystat ; check to see if we're looking for a high or low on y goto yhigh ; it was high, we're looking for low. ylow btfsc ystep ; check step input for y skip if 0 (ylow tag not used, for reading code only) call ydostep ; if it has gone high step x.. goto znext ; do z next... yhigh ; attempt to discharge cap on ystep input. bsf STATUS,RP0 ; select register page 1 for option etc. bcf TRISC,2 ; turn it into an output for 0.2us, which will discharge the cap, like. bsf TRISC,2 bcf STATUS,RP0 ; select register page 0 again. btfss ystep ; check the input, see if it's gone low. bcf ystat ; if it has gone low, clear it's status flag. znext btfsc zstat ; check to see if we're looking for a high or low on z goto zhigh ; it was high, we're looking for low. zlow btfsc zstep ; check step input for z skip if 0 (zlow tag not used, for reading code only) call zdostep ; if it has gone high step z.. goto loop ; and back to the start again! zhigh ; attempt to discharge cap on zstep input. bsf STATUS,RP0 ; select register page 1 for option etc. bcf TRISC,4 ; turn it into an output for 0.2us, which will discharge the cap, like. bsf TRISC,4 bcf STATUS,RP0 ; select register page 0 again. btfss zstep ; check the input, see if it's gone low. bcf zstat ; if it has gone low, clear it's status flag. goto loop ; loopy-de-loop ; we're not enabled if we get this far... ; first turn outputs off via TRIS bits... noten bsf STATUS,RP0 ; select register page 1 for option etc. movlw amodeo ; 'off' settings for trisb and trisc movwf TRISA movlw bmodeo movwf TRISB bcf STATUS,RP0 ; select register page 0 again. notenl btfss enable ; if it's still high, skip a bit. goto enabled ; it was low again, go back to the main loop. bsf led ; turn on led movlw 4 ; four loops through delay.. call ldelay bcf led btfss enable ; if it's still high, skip a bit. goto enabled ; it was low again, go back to the main loop. movlw 4 ; four loops through delay.. call ldelay goto notenl ; check again. enabled clrf PORTC ; this is here because the read-modify-write used to flash the LED could leave PORTC in an unknown state. bsf STATUS,RP0 ; select register page 1 for option etc. movlw amode ; 'on' settings for trisa and trisb movwf TRISA movlw bmode movwf TRISB bcf STATUS,RP0 ; select register page 0 again. goto loop ; back to the main loopy thing. ; this is where we wind up for a watch dog reset... sos movlw cmode ; set C modes so I can drive the LED. (Already in register page 1) movwf TRISC bcf STATUS,RP0 ; select register page 0 again. ; three short, three long flashes... sosloop movlw 20 ; bit of a pause... call ldelay bsf led ; short movlw 2 call ldelay bcf led movlw 4 call ldelay bsf led ; short movlw 2 call ldelay bcf led movlw 4 call ldelay bsf led ; short movlw 2 call ldelay bcf led movlw 8 call ldelay bsf led ; long movlw 6 call ldelay bcf led movlw 4 call ldelay bsf led ; long movlw 6 call ldelay bcf led movlw 4 call ldelay bsf led ; long movlw 6 call ldelay bcf led movlw 8 call ldelay bsf led ; short movlw 2 call ldelay bcf led movlw 4 call ldelay bsf led ; short movlw 2 call ldelay bcf led movlw 4 call ldelay bsf led ; short movlw 2 call ldelay bcf led goto sosloop end